package com.xxxx.seckill.controller;


import com.xxxx.seckill.config.AccessLimit;
import com.xxxx.seckill.exception.GlobalException;
import com.xxxx.seckill.pojo.SeckillMessage;
import com.xxxx.seckill.pojo.SeckillOrder;
import com.xxxx.seckill.pojo.User;
import com.xxxx.seckill.rabbitmq.MQSender;
import com.xxxx.seckill.service.IGoodsService;
import com.xxxx.seckill.service.IOrderService;
import com.xxxx.seckill.service.ISeckillOrderService;
import com.xxxx.seckill.util.JsonUtil;
import com.xxxx.seckill.vo.GoodsVo;
import com.xxxx.seckill.vo.RespBean;
import com.xxxx.seckill.vo.RespBeanEnum;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Controller
@RequestMapping("seckill")
@Slf4j
public class SecKillController implements InitializingBean {
    @Autowired
    private IGoodsService goodsService;
    @Autowired
    private ISeckillOrderService seckillOrderService;
	@Autowired
	private IOrderService orderService;
	@Autowired
	private RedisTemplate redisTemplate;
	@Autowired
	private MQSender mqSender;
	@Autowired
	private RedisScript<Long> script;

	private Map<Long, Boolean> EmptyStockMap = new HashMap<>();

	/*
    优化前：1千*10*3，QPS：877
    缓存QPS：1479
    优化QPS：2701
     */
//    @RequestMapping("/doSeckill2")
//    public String doSeckill2(Model model, User user,Long goodsId){
//        if(user==null){
//            return "login";
//        }
//		model.addAttribute("user",user);
//		GoodsVo goods = goodsService.findGoodsVoByGoodsId(goodsId);
//		//判断库存
//		if (goods.getStockCount() < 1) {
//			model.addAttribute("errmsg", RespBeanEnum.EMPTY_STOCK.getMessage());
//		}
//		//判断是否重复抢购
//		 SeckillOrder seckillOrder =
//		 		seckillOrderService.getOne(new QueryWrapper<SeckillOrder>().eq("user_id", user.getId()).eq("goods_id",
//		 				goodsId));
//		if (seckillOrder != null) {
//			model.addAttribute("errmsg",RespBeanEnum.REPEATE_ERROR.getMessage());
//			return "secKillFail";
//		}
//		Order order = orderService.seckill(user, goods);
//		model.addAttribute("order",order);
//		model.addAttribute("goods",goods);
//		return "orderDetail";
//    }


	@RequestMapping(value = "/{path}/doSeckill", method = RequestMethod.POST)
	@ResponseBody
	public RespBean doSeckill(@PathVariable String path, User user, Long goodsId) {
		if (user == null) {
			return RespBean.error(RespBeanEnum.SESSION_ERROR);
		}
		ValueOperations valueOperations = redisTemplate.opsForValue();
		boolean check = orderService.checkPath(user, goodsId, path);
		if (!check) {
			return RespBean.error(RespBeanEnum.REQUEST_ILLEGAL);
		}
		//判断是否重复抢购
		SeckillOrder seckillOrder =
				(SeckillOrder) redisTemplate.opsForValue().get("order:" + user.getId() + ":" + goodsId);
		if (seckillOrder != null) {
			return RespBean.error(RespBeanEnum.REPEATE_ERROR);
		}
		//内存标记，减少Redis的访问
		if (EmptyStockMap.get(goodsId)) {
			return RespBean.error(RespBeanEnum.EMPTY_STOCK);
		}
		//预减库存
//		 Long stock = valueOperations.decrement("seckillGoods:" + goodsId);
		Long stock = (Long) redisTemplate.execute(script, Collections.singletonList("seckillGoods:" + goodsId),
				Collections.EMPTY_LIST);
		if (stock < 0) {
			EmptyStockMap.put(goodsId, true);
			valueOperations.increment("seckillGoods:" + goodsId);
			return RespBean.error(RespBeanEnum.EMPTY_STOCK);
		}
		SeckillMessage seckillMessage = new SeckillMessage(user, goodsId);
		mqSender.sendSeckillMessage(JsonUtil.object2JsonStr(seckillMessage));
		return RespBean.success();

//		GoodsVo goods = goodsService.findGoodsVoByGoodsId(goodsId);
//		//判断库存
//		if (goods.getStockCount() < 1) {
//			model.addAttribute("errmsg", RespBeanEnum.EMPTY_STOCK.getMessage());
//			return RespBean.error(RespBeanEnum.EMPTY_STOCK);
//		}
//		//判断是否重复抢购
//		SeckillOrder seckillOrder =
//				(SeckillOrder) redisTemplate.opsForValue().get("order:" + user.getId() + ":" + goodsId);
//		if (seckillOrder != null) {
//			model.addAttribute("errmsg",RespBeanEnum.REPEATE_ERROR.getMessage());
//			return RespBean.error(RespBeanEnum.REPEATE_ERROR);
//		}
//		Order order = orderService.seckill(user, goods);
//		return RespBean.success(order);

	}


	@RequestMapping(value = "/result", method = RequestMethod.GET)
	@ResponseBody
	public RespBean getResult(User user, Long goodsId) {
		if (user == null) {
			return RespBean.error(RespBeanEnum.SESSION_ERROR);
		}
		Long orderId = seckillOrderService.getResult(user, goodsId);
		return RespBean.success(orderId);
	}


	@AccessLimit(second=5,maxCount=5,needLogin=true)
	@RequestMapping(value = "/path", method = RequestMethod.GET)
	@ResponseBody
	public RespBean getPath(User user, Long goodsId, String captcha) {
		if (user == null) {
			return RespBean.error(RespBeanEnum.SESSION_ERROR);
		}
		boolean check = orderService.checkCaptcha(user, goodsId, captcha);
		if (!check) {
			return RespBean.error(RespBeanEnum.ERROR_CAPTCHA);
		}
		String str = orderService.createPath(user, goodsId);
		return RespBean.success(str);
	}

	@RequestMapping(value = "/captcha", method = RequestMethod.GET)
	public void generateCaptcha(User user, Long goodsId, HttpServletResponse response) {
		if (user == null || goodsId < 0) {
			throw new GlobalException(RespBeanEnum.REQUEST_ILLEGAL);
		}

		// 设置响应头，防止缓存
		response.setContentType("image/jpeg");
		response.setHeader("Pragma", "No-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);

		// 生成随机数学运算题目
		int num1 = (int) (Math.random() * 10); // 0-9随机数
		int num2 = (int) (Math.random() * 10);
		char operator = generateRandomOperator(); // 随机运算符 (+, -, *)
		int result = calculateResult(num1, num2, operator); // 计算结果
		String captchaText = num1 + " " + operator + " " + num2;

		// 将验证码计算结果存入 Redis，有效期 5 分钟
		redisTemplate.opsForValue().set("captcha:" + user.getId() + ":" + goodsId, String.valueOf(result), 300, TimeUnit.SECONDS);

		// 生成图片并输出
		try {
			BufferedImage captchaImage = createCaptchaImage(captchaText); // 创建图片
			ImageIO.write(captchaImage, "jpeg", response.getOutputStream()); // 输出到响应流
		} catch (IOException e) {
			log.error("验证码生成失败", e.getMessage());
		}
	}

	/**
	 * 随机生成一个运算符 (+, -, *)
	 */
	private char generateRandomOperator() {
		char[] operators = {'+', '-', '*'};
		int index = (int) (Math.random() * operators.length);
		return operators[index];
	}

	/**
	 * 根据操作符计算表达式的结果
	 */
	private int calculateResult(int num1, int num2, char operator) {
		switch (operator) {
			case '+': return num1 + num2;
			case '-': return num1 - num2;
			case '*': return num1 * num2;
			default: throw new IllegalArgumentException("不支持的操作符: " + operator);
		}
	}

	/**
	 * 手写实现验证码图片生成
	 */
	private BufferedImage createCaptchaImage(String captchaText) {
		int width = 150;  // 图片宽度
		int height = 50;  // 图片高度
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics2D g = image.createGraphics();

		// 设置背景颜色
		g.setColor(getRandomColor(200, 255));
		g.fillRect(0, 0, width, height);

		// 设置字体
		g.setFont(new Font("Arial", Font.BOLD, 32));

		// 绘制随机字符
		g.setColor(getRandomColor(0, 150));
		g.drawString(captchaText, 20, 35);

		// 添加一些干扰线
		for (int i = 0; i < 5; i++) {
			g.setColor(getRandomColor(50, 200));
			int x1 = (int) (Math.random() * width);
			int y1 = (int) (Math.random() * height);
			int x2 = (int) (Math.random() * width);
			int y2 = (int) (Math.random() * height);
			g.drawLine(x1, y1, x2, y2);
		}

		// 添加一些噪点
		for (int i = 0; i < 50; i++) {
			int x = (int) (Math.random() * width);
			int y = (int) (Math.random() * height);
			int rgb = getRandomColor(100, 250).getRGB();
			image.setRGB(x, y, rgb);
		}

		g.dispose();
		return image;
	}

	/**
	 * 随机生成颜色
	 */
	private Color getRandomColor(int min, int max) {
		if (min > 255) min = 255;
		if (max > 255) max = 255;
		int r = min + (int) (Math.random() * (max - min));
		int g = min + (int) (Math.random() * (max - min));
		int b = min + (int) (Math.random() * (max - min));
		return new Color(r, g, b);
	}



	@Override
	public void afterPropertiesSet() throws Exception {
		List<GoodsVo> list = goodsService.findGoodsVo();
		if (CollectionUtils.isEmpty(list)) {
			return;
		}
		list.forEach(goodsVo -> {
				redisTemplate.opsForValue().set("seckillGoods:" + goodsVo.getId(), goodsVo.getStockCount());
				EmptyStockMap.put(goodsVo.getId(), false);
			}
		);
	}

}
